Android — 自定义View(六)之Path 贝塞尔曲线

前言

忍不住要吐槽一下了,自定义View系列已经写了五篇了,有点烦了。在看这节的标题,贝塞尔曲线,哇,以前曾经了解过一点,感觉好难啊。但是要实现很酷炫的效果,离不开贝塞尔曲线,怎么办?还能怎么办,学吧学吧,向现实低头!

其实,我只是想放一个这个图而已,2333333

好了,言归正传。按照惯例,先回顾上一节所学的内容,Path的基本操作。首先浮现在脑海中的是moveTo()、LineTo()、setLastPoint()这三个方法,也是比较容易理解的,重点是要分别moveTo()和setLastPoint()对之前绘制内容是否有影响的区别。紧接着,我们讲到了close()方法用来封闭路径,之后就是addXxx()一系列方法,值得一提的就是该方法中的一个枚举类型的参数,用来控制是顺时针(CW)还是逆时针(CCW)来绘制图形。

本节目录如下:

  1. 贝塞尔曲线原理简介
  2. 二阶贝塞尔曲线示例

贝塞尔曲线原理简介

对于一阶贝塞尔曲线是没有控制点的,实际上就是lineTo()方法。拿二阶贝塞尔曲线示例:

A、C 是两个数据点,用来确定曲线的起始和结束位置,而B是控制点,用来确定曲线的弯曲程度。以上确定 F 点则是通过比例绘制出来的,即:

AD / AB = BE / BC = DF / DE

动态如下:

三阶贝塞尔曲线则是有两个数据点两个控制点:

那下面就实践一下分别对应的两个方法该怎么用。

二阶贝塞尔曲线示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
public class SecondBesselCurveView extends View {
private Paint mPaint;
private int mWidth;
private int mHeight;
private PointF startPoint,endPoint, controlPoint;
private void init() {
mPaint = new Paint();
mPaint.setStrokeWidth(3);
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.STROKE);
}
public SecondBesselCurveView(Context context) {
super(context);
init();
}
public SecondBesselCurveView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public SecondBesselCurveView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mWidth = w / 2;
mHeight = h / 2;
startPoint = new PointF(mWidth-200, mHeight);
endPoint = new PointF(mWidth + 200, mHeight);
controlPoint = new PointF(mWidth, mHeight - 200);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//绘制数据点和控制点
canvas.drawPoint(startPoint.x, startPoint.y, mPaint);
canvas.drawPoint(endPoint.x, endPoint.y, mPaint);
canvas.drawPoint(controlPoint.x, controlPoint.y, mPaint);
//画辅助线
mPaint.setAlpha(127);
mPaint.setColor(Color.BLACK);
canvas.drawLine(startPoint.x, startPoint.y, controlPoint.x, controlPoint.y, mPaint);
canvas.drawLine(endPoint.x, endPoint.y, controlPoint.x, controlPoint.y, mPaint);
//画贝塞尔曲线
mPaint.setColor(Color.RED);
mPaint.setStrokeWidth(8);
Path path = new Path();
path.moveTo(startPoint.x, startPoint.y);
path.quadTo(controlPoint.x, controlPoint.y, endPoint.x, endPoint.y);
canvas.drawPath(path, mPaint);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
//根据触摸点更新控制点
controlPoint.x = event.getX();
controlPoint.y = event.getY();
invalidate();
return true;
}
}

也比较容易理解,首先是将起点设置为起始数据点,然后再在Path.quadTo()中传递控制点和终点的坐标值,最后用Canvas绘制出来,效果如下:

对于三阶贝塞尔曲线则是在Path.cubicTo()多加一个控制点的坐标值,在这里就不演示了。

我们一直都向往,面朝大海,春暖花开。 但是几人能做到,心中有爱,四季不败?